package von.seiji.cn.other;

import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestUtil;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import org.junit.Test;

import java.util.*;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

public class Railway {

    //各线路编码
    static List<String> aList = Lists.newArrayList();
    static List<String> bList = Lists.newArrayList();
    static List<String> cList = Lists.newArrayList();
    static List<String> dList = Lists.newArrayList();
    static List<String> eList = Lists.newArrayList();
    static List<String> fList = Lists.newArrayList();

    static Map<String, ArrayList<String>> lineMap = Maps.newHashMap();

    //线路交点名称
    static List<ArrayList<String>> intersectionList = Lists.newArrayList();


    static {

        Dict dict = Dict.of("A", 7, "B", 8, "C", 6, "D", 6, "E", 7, "F", 8);


        intersectionList = Lists.newArrayList(
                Lists.newArrayList("A1", "D4"),
                Lists.newArrayList("A2", "F6"),
                Lists.newArrayList("A4", "B6"),
                Lists.newArrayList("B1", "F2"),
                Lists.newArrayList("B2", "D2"),
                Lists.newArrayList("B3", "E2"),
                Lists.newArrayList("B5", "E4"),
                Lists.newArrayList("C1", "F1"),
                Lists.newArrayList("C2", "D1"),
                Lists.newArrayList("C3", "E1"),
                Lists.newArrayList("D3", "F4")

        );

        lineMap = Maps.asMap(Sets.<String>newHashSet("A", "B", "C", "D", "E", "F"), input ->
                ((ArrayList<String>) IntStream.range(0, dict.getInt(input)).mapToObj(item -> {
                    String stop = input + item;
                    return intersectionList.stream().filter(item2 -> item2.contains(stop)).findFirst().map(item2 ->
                            DigestUtil.md5Hex(item2.stream().sorted().collect(Collectors.joining()))
                    ).orElseGet(() -> DigestUtil.md5Hex(stop));
                }).collect(Collectors.toList()))
        );

        aList = Lists.newArrayList(
                lineMap.get("A")
//                "A0", "A1", "A2", "A3", "A4", "A5", "A6"
//                "d88c146dfafdea37a837778a92415bc2", "2221a983f5f6216c204666d6e3d84116", "644ea94bd83e7c53d1ef3a9f8908ee28", "6593d7b12fd418cdb35bbf438de72f66", "9c3e1857f8f1f08d279347ac94b6ef3e", "c6f2f93133905f75da4b02ccc19ab66a", "0b3d5609ee81e50809b7351e848e4698"

        );
        bList = Lists.newArrayList(
                lineMap.get("B")
//                "B0", "B1", "B2", "B3", "B4", "B5", "B6", "B7"
//                "4c769c2c9989abb9fa024ab9930270e5", "512f7d9c0d8ab0e277e882c1438ef497", "f5586fb769829c4151bec70da6b80756", "a8fdd1d1088f2736c3ab5f4a570d6f0f", "d5d4cc7b09d1843517acc9361f8f665e", "72996715976ae3d6fcdc03ba7a2d1d78", "9c3e1857f8f1f08d279347ac94b6ef3e", "d8498108dd603522047564a8da7be94c"
        );
        cList = Lists.newArrayList(
                lineMap.get("C")
//               "C0", "C1", "C2", "C3", "C4", "C5"
//                "9c5959e6f08f10d0edbadf5be1f33c53", "16f70eb84d7710ff96ea5b33967d31af", "c724ec3a55b3a69d87dc6fd93572eb55", "69ffb20970adb6be9fce903a7b948b14", "b713e6323a68d3ddabf4855826c50148", "fea813d4ddba3c46cf8b8e664b92cdaa"

        );
        dList = Lists.newArrayList(
                lineMap.get("D")
//               "D0",  "D1", "D2", "D3", "D4", "D5"
//                "0e3e06c992d1ead056a6861bb46b28a8", "c724ec3a55b3a69d87dc6fd93572eb55", "f5586fb769829c4151bec70da6b80756", "dc827e042b9dc5bdfdd2e7269d61d253", "2221a983f5f6216c204666d6e3d84116", "ea8ea3bfaa27cf4c2f61470447c87eea"
        );
        eList = Lists.newArrayList(
                lineMap.get("E")
//                "E0", "E1", "E2", "E3", "E4", "E5", "E6"
//                "0e51a87ec173dd9534a056a403c85881", "69ffb20970adb6be9fce903a7b948b14", "a8fdd1d1088f2736c3ab5f4a570d6f0f", "b29bcbb0f188e0093434a5f213285f46", "72996715976ae3d6fcdc03ba7a2d1d78", "f9f2d672039ed5d04839b769ad71e1b0", "247116319466c7be96c6ac3ab87984cb"
        );
        fList = Lists.newArrayList(
                lineMap.get("F")
//                "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7"
//                "ee0c8bd6520d8fb37a28c61189d0e821", "16f70eb84d7710ff96ea5b33967d31af", "512f7d9c0d8ab0e277e882c1438ef497", "4b6bf4b531770872d4328ce69bef5627", "dc827e042b9dc5bdfdd2e7269d61d253", "37f438df6a6d5ba4c17ef8ca58562f00", "644ea94bd83e7c53d1ef3a9f8908ee28", "47489eb597b7db34caa24b1fc78fc839"
        );

    }


    @Test
    public void testPlan() {

        String start = nameByCode("F0");
        String end = nameByCode("A6");
//        String end = null;

        List<ArrayList<String>> routePlan = planing(start, end);
        routePlan.forEach(System.out::println);
        System.out.println("===================================");
        List<List<String>> collect1 = routePlan.stream().map(item -> item.stream().map(this::findCode).collect(Collectors.toList())).collect(Collectors.toList());

        System.out.println("所有路线简编：");
        routePlan.stream().map(item -> item.stream().map(this::findCode).collect(Collectors.toList())).forEach(System.err::println);
        System.out.println("完整路线简编：");
        List<List<Map<String, ArrayList<String>>>> collect = routePlan.stream().map(this::summaryAllStop).map(item ->
                item.stream()
                        .map(item1 -> item1.entrySet().stream()
                                .collect(Collectors.toMap(item2 -> item2.getKey(), item2 ->
                                        Lists.newArrayList(
                                                item2.getValue().stream().map(this::findCode).collect(Collectors.toList())
                                        )
                                ))
                        ).collect(Collectors.toList())
        ).collect(Collectors.toList());
        collect.forEach(System.out::println);

/*
        System.out.println("---------------测试---------------");
        List<Map<String, ArrayList<String>>> maps = collect.get(0);
        maps.get(1).put("T", Lists.newArrayList("CC", "EE"));
        System.err.println("maps = " + maps);
        List<Map<String, ArrayList<String>>> analysis = analysis(maps);
        System.out.println("analysis = " + analysis);
        analysis.forEach(System.out::println);
        System.out.println("---------------测试---------------");*/

        System.out.println("简编路线整合：");

        List<List<Map<String, ArrayList<String>>>> list = collect.stream().map(this::analysis).collect(Collectors.toList());
        list.forEach(System.out::println);


        System.out.println("========================================");
        testRouteCombo(start, end);
    }

    public List<ArrayList<String>> planing(String start, String end) {
        Assert.notBlank(start, "起始点不能为空");
        Assert.isTrue(StrUtil.isEmpty(end)
                || !start.equals(end), "结束点要么为空，否则不能和其实点相同");
        return planing(end, candidates -> {
                    return candidates.stream().allMatch(item ->
                            item.contains(end) || findNextLines(item).isEmpty()
                    );
        },  () ->
                Optional.of(start).map(item ->
                        findLine(item).stream().flatMap(beginLine -> {
                            //判断终点是否在该线上(不管起点是终点是否同线，都应该继续，同线不代表最优线路)
                            List<String> hubs = lineMap.get(beginLine).contains(end)
                                    ? appendToList(findHubs(beginLine, item)
                                    .stream().filter(hub ->
                                            summaryStop(item, end).size() > summaryStop(item, hub).size()).collect(Collectors.toList()), end)
                                    : findHubs(beginLine, item);
                            return hubs.stream().map(hub -> Lists.newArrayList(item, hub));
                        }).collect(Collectors.toList())
                ).orElse(null)
        );

    }

    private List<ArrayList<String>> planing(String destination, Predicate<List<ArrayList<String>>> end, Supplier<List<ArrayList<String>>> supplier) {
        List<ArrayList<String>> candidates = supplier.get();
        if (!candidates.isEmpty()) {
            return end.test(candidates) ? Optional.ofNullable(destination).map(item ->
                    // 过滤包含终点的线路
                    candidates.stream()
                            .filter(line -> line.contains(item)).collect(Collectors.toList())
            ).orElse(candidates)
                    : planing(destination, collect -> {
                        return end.test(candidates) || candidates.size() == collect.size();
                    }, () ->
                    candidates.stream().flatMap(candidate -> {
                        List<String> nextLines = findNextLines(candidate);

                        return !candidate.contains(destination) && !nextLines.isEmpty() ? nextLines.stream().flatMap(nextLine -> {

                            String last = Lists.newLinkedList(candidate).getLast();
                            List<String> usedLines = findUsedLines(candidate);
                            //判断终点是否在该线上
                            List<String> hubs = lineMap.get(nextLine).contains(destination)
                                    ? appendToList(findHubs(nextLine, last)
                                    .stream().filter(hub ->
                                            summaryStop(last, destination).size() > summaryStop(last, hub).size())
                                    .collect(Collectors.toList()), destination) : findHubs(nextLine, last);

                            List<String> collect = hubs.stream().filter(hub ->
                                    // 枢纽所在的所有可能的线不能是已经路过的线
                                    findLine(hub).stream().allMatch(possibleLine ->
                                            !usedLines.contains(possibleLine)
                                    )).filter(hub ->
                                    // 不仅该枢纽不能在以路过的线上，而且该点到枢纽中的站点也不能经过以路过的线
                                    //这些条件造成了一个重大的问题：虽然在这里作为路线终止的条件，却不能成为方法递归结束的条件
                                    summaryStop(last, hub).entrySet().stream().map(Map.Entry::getValue).anyMatch(possibleLine ->
                                            possibleLine.stream().filter(stop -> !last.equals(stop)).allMatch(possibleStop ->
                                                    findLine(possibleStop).stream().noneMatch(usedLines::contains)
                                            )
                                    )
                            ).collect(Collectors.toList());
//                            return collect.stream().map(hub -> appendToList((ArrayList<String>) candidate.clone(), hub));
                            return collect.isEmpty()
                                    ? Stream.of((ArrayList<String>) candidate.clone()).map(ArrayList::new)
                                    : collect.stream().map(hub -> appendToList((ArrayList<String>) candidate.clone(), hub));

                        }) : Stream.of((ArrayList<String>) candidate.clone()).map(ArrayList::new);

                    }).collect(Collectors.toList())
            );

        }
        return ListUtil.<ArrayList<String>>empty();
    }


    <E> ArrayList<E> appendToList(List<E> elements, E... elem) {

        ArrayList<E> es1 = Lists.newArrayList(elements);
        Arrays.stream(elem).filter(Objects::nonNull).forEach(es1::add);
        return es1;
    }

    <E> ArrayList<E> comboToList(List<E> elements, List<E> source) {

        ArrayList<E> es1 = Lists.newArrayList(elements);
        es1.addAll(source);
        return es1;
    }


    /**
     * 输入起始点和终点（可选）计算路线
     *
     * @param obj
     * @param destination
     * @return
     */
    public List<ArrayList<String>> routeCombo(Object obj, String destination) {

        if (obj instanceof String) {

            List<ArrayList<String>> orElse = Optional.of((String) obj).map(item ->
                    findLine(item).stream().flatMap(beginLine ->
                            {
                                boolean lastLine = lineMap.get(beginLine).contains(destination);
                                return !lastLine
                                        ? findHubs(beginLine, item).stream().map(hub -> Lists.newArrayList(item, hub))
                                        : Stream.of(Lists.newArrayList((String) obj, destination)).map(Lists::newArrayList);
                            }
                    ).collect(Collectors.toList())
            ).orElse(null);
            return routeCombo(orElse, destination);
        } else {
            List<ArrayList<String>> candidates = (List<ArrayList<String>>) obj;
            List<ArrayList<String>> end = candidates.stream().flatMap(candidate -> {
                List<String> nextLines = findNextLines(candidate);

                return !candidate.contains(destination) && !nextLines.isEmpty() ? nextLines.stream().flatMap(nextLine -> {
                    boolean lastLine = lineMap.get(nextLine).contains(destination);
                    List<String> usedLines = findUsedLines(candidate);
                    String last = Lists.newLinkedList(candidate).getLast();

                    // 该站点到终点之间的站点不能在任意一条以路过的线上
                   /* boolean pass = summaryStop(last, destination).entrySet().stream().map(Map.Entry::getValue).anyMatch(possibleLine ->
                            possibleLine.stream().filter(stop -> !last.equals(stop)).allMatch(possibleStop ->
                                    findLine(possibleStop).stream().noneMatch(usedLines::contains)
                            )
                    );*/

                    ArrayList<String> o = lastLine
                            ? Lists.newArrayList(destination) : ((ArrayList<String>) findHubs(nextLine, last)
                            .stream().filter(hub ->
                                    findLine(hub).stream().allMatch(possibleLine ->
                                            !usedLines.contains(possibleLine)
                                    )).collect(Collectors.toList()));
                    return o.isEmpty() ? Stream.of((ArrayList<String>) candidate.clone()).map(ArrayList::new) : o.stream().map(item2 ->
                            appendToList((ArrayList<String>) candidate.clone(), item2)
                    );
                }) : Stream.of((ArrayList<String>) candidate.clone()).map(ArrayList::new);

            }).collect(Collectors.toList());
            if (candidates.size() != end.size()) {
                return routeCombo(end, destination);
            }
            return Optional.ofNullable(destination).map(item ->
                    end.stream()
                            .filter(line -> line.contains(item)).collect(Collectors.toList())
            ).orElse(end);
        }
    }


//    @Test
    public void testRouteCombo(String start, String end) {
        System.out.println("----------------------------------旧版---------------------------------");

//        String start = nameByCode("B3");
//        String end = nameByCode("F4");
        List<ArrayList<String>> arrayLists = routeCombo(start, end);
        System.out.println("所有路线简编：");
        arrayLists.stream().map(item -> item.stream().map(this::findCode).collect(Collectors.toList())).forEach(System.out::println);
        System.out.println("完整路线简编：");
        List<List<Map<String, ArrayList<String>>>> collect = arrayLists.stream().map(this::summaryAllStop).map(item ->
                item.stream()
                        .map(item1 -> item1.entrySet().stream()
                                .collect(Collectors.toMap(item2 -> item2.getKey(), item2 ->
                                        Lists.newArrayList(
                                                item2.getValue().stream().map(this::findCode).collect(Collectors.toList())
                                        )
                                ))
                        ).collect(Collectors.toList())
        ).collect(Collectors.toList());
        collect.forEach(System.out::println);

        System.out.println("简编路线整合：");

        List<List<Map<String, ArrayList<String>>>> list = collect.stream().map(this::analysis).collect(Collectors.toList());
        list.forEach(System.out::println);


    }


    public List<Map<String, ArrayList<String>>> analysis(List<Map<String, ArrayList<String>>> maps) {
        Queue<Map<String, ArrayList<String>>> queue = new LinkedList<>();
        maps.forEach(queue::add);
        return analysis(() -> {
            if (!queue.isEmpty()) {
                Map<String, ArrayList<String>> poll = queue.poll();
                return poll.entrySet().stream().map(item ->
                        Maps.asMap(Sets.newHashSet(item.getKey()), input ->
                                Lists.newArrayList(item.getValue())
                        )
                ).collect(Collectors.toList());
            }
            return Lists.newArrayList();
        }, queue);
    }

    private List<Map<String, ArrayList<String>>> analysis(Supplier<List<Map<String, ArrayList<String>>>> analyse, Queue<Map<String, ArrayList<String>>> queue) {
        List<Map<String, ArrayList<String>>> apply = analyse.get();
        if (apply.isEmpty() || queue.isEmpty()) {
            return apply;
        } else {
            return analysis(() -> {
                Map<String, ArrayList<String>> poll = queue.poll();
                return apply.stream().map(Map::entrySet).flatMap(entrySet ->
                        entrySet.stream().flatMap(item ->
                                poll.entrySet().stream().map(item1 ->
                                        Maps.asMap(Sets.newHashSet(item.getKey() + "_" + item1.getKey()), input ->
                                                ((ArrayList<String>) comboToList((ArrayList<String>) item.getValue().clone(),
                                                        item1.getValue()).stream().distinct().collect(Collectors.toList()))
                                        )
                                )
                        )
                ).collect(Collectors.toList());
            }, queue);
        }
    }


    /**
     * 根据某个站名求路线名
     *
     * @return
     */
    public List<String> findLine(String stop) {

        return lineMap.entrySet().stream()
                .filter(item -> item.getValue().contains(stop))
                .map(Map.Entry::getKey).collect(Collectors.toList());

    }

    @Test
    public void testFindLine() {
        List<String> d3F4 = findLine(DigestUtil.md5Hex("D3F4"));
        System.out.println("d3F4 = " + d3F4);
        ArrayList<String> strings = Lists.newArrayList("D1", "A");
        boolean b = d3F4.stream().noneMatch(strings::contains);
        System.out.println("b = " + b);
    }

    /**
     * 根据已经通过的站点找到下一站所在的路线
     *
     * @param stops
     * @return
     */
    public List<String> findNextLines(List<String> stops) {

        Map<String, Long> collect = stops.stream().map(this::findLine)
                .flatMap(List::stream).collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));

        String last = Lists.newLinkedList(stops).getLast();

        //最后这个站点所在的路线（可能有多个，即交汇处）
        List<String> lastLineNames = findLine(last);

        return collect.entrySet().stream().filter(item ->
                item.getValue() == 1).map(Map.Entry::getKey)
                .filter(item -> lastLineNames.contains(item)).collect(Collectors.toList());
    }


    @Test
    public void testFindNextLine() {
        ArrayList<String> strings = Lists.newArrayList("A1D4", "C2D1", "C3E1", "B3E2", "B1F2");
        List<String> collect = strings.stream().map(this::nameByCode).collect(Collectors.toList());
        System.out.println("collect = " + collect);
        List<String> nextLines = findNextLines(collect);
        System.out.println("nextLine = " + nextLines);
    }

    /**
     * 根据简编获取站名（如A1(实际编码：A1D4)）
     */
    public String nameByCode(String code) {
        return intersectionList.stream().filter(item2 -> item2.contains(code)).findFirst().map(item2 ->
                DigestUtil.md5Hex(item2.stream().sorted().collect(Collectors.joining()))
        ).orElseGet(() -> DigestUtil.md5Hex(code));
    }

    /**
     * 根据已经通过的站点找到以乘坐过的路线
     *
     * @param stops
     * @return
     */
    public List<String> findUsedLines(List<String> stops) {

        Map<String, Long> collect = stops.stream().map(this::findLine)
                .flatMap(List::stream).collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
        return collect.entrySet().stream().filter(item -> item.getValue() > 1).map(Map.Entry::getKey).collect(Collectors.toList());
    }

    @Test
    public void testFindUsedLines() {
        ArrayList<String> strings = Lists.newArrayList("A0", "A1", "C2", "C1");
        List<String> collect = strings.stream().map(this::nameByCode).collect(Collectors.toList());
        System.out.println("collect = " + collect);
        findUsedLines(collect).forEach(System.out::println);
    }

    /**
     * 根据路线获取线路枢纽(不包括指定的站)
     */
    public List<String> findHubs(String lineName, String exceptStop) {
        ArrayList<String> stops = lineMap.get(lineName);

        return Optional.ofNullable(exceptStop).map(item ->
                stops.stream().filter(stop -> !exceptStop.equals(stop)).collect(Collectors.toList())
        ).orElse(stops)
                .stream().filter(item ->
                        lineMap.entrySet().stream().filter(link ->
                                !lineName.equals(link.getKey()))
                                .map(Map.Entry::getValue).anyMatch(otherLine -> otherLine.contains(item))
                ).collect(Collectors.toList());
    }

    @Test
    public void testFindHubs() {
        List<String> a = findHubs("A", null);
        System.out.println("a = " + a);
        System.out.println(a.stream().map(item -> findCode(item)).collect(Collectors.toList()));

    }

    /**
     * 根据站点获取编码
     */
    public String findCode(String stop) {
        List<String> line = findLine(stop);
        String collect = lineMap.entrySet().stream().filter(item -> line.contains(item.getKey()))
                .map(item -> item.getKey().toString() + item.getValue().indexOf(stop))
                .sorted().collect(Collectors.joining());

        return collect;
    }

    @Test
    public void testFindCode() {

        String stop = "d88c146dfafdea37a837778a92415bc2";
        String code = findCode(stop);
        System.out.println("code = " + code);
        System.out.println(ResourceBundle.getBundle("railway").getString(code));
    }


    /**
     * 判断两个站点是否在一条路线上（并获取该路线）
     *
     * @param begin
     * @param end
     * @return
     */
    public List<String> sameLine(String begin, String end) {
        return lineMap.entrySet().stream().filter(item ->
                item.getValue().containsAll(Lists.newArrayList(begin, end)))
                .map(Map.Entry::getKey).collect(Collectors.toList());
    }

    @Test
    public void testSameLine() {
        List<String> line = sameLine("2221a983f5f6216c204666d6e3d84116", "f5586fb769829c4151bec70da6b80756");
        System.out.println("line = " + line);
        List<String> line1 = sameLine("2221a983f5f6216c204666d6e3d84116", "644ea94bd83e7c53d1ef3a9f8908ee28");
        System.out.println("line1 = " + line1);
        List<String> line2 = sameLine("f5586fb769829c4151bec70da6b80756", "644ea94bd83e7c53d1ef3a9f8908ee28");
        System.out.println("line2 = " + line2);
    }

    /**
     * 获取包含两个站点间的所有站点（同一线路）
     */
    public Map<String, List<String>> summaryStop(String begin, String end) {
        List<String> sameLine = sameLine(begin, end);
        return sameLine.stream().collect(Collectors.toMap(lineName -> lineName, lineName -> {
            List<String> line = lineMap.get(lineName);
            int i = line.indexOf(begin), j = line.indexOf(end);
            return IntStream.range(Math.min(i, j), Math.max(i, j) + 1)
                    .mapToObj(item -> line.get(item)).sorted(Comparator.comparing(item -> Integer.compare(j, i) * line.indexOf(item))).collect(Collectors.toList());
        }));
    }

    @Test
    public void tesSummaryStop() {
        Map<String, List<String>> stop = summaryStop(DigestUtil.md5Hex("B1F2"), DigestUtil.md5Hex("A2F6"));
        System.out.println("stop = " + stop);
        stop.keySet().stream().map(item ->
                stop.get(item).stream().map(this::findCode).collect(Collectors.toList())
        ).forEach(System.out::println);
    }

    public List<Map<String, List<String>>> summaryAllStop(List<String> stops) {
        return IntStream.range(0, stops.size() - 1).mapToObj(item ->
                summaryStop(stops.get(item), stops.get(item + 1))
        ).collect(Collectors.toList());
    }

    @Test
    public void testSummaryAllStop() {
        List<Map<String, List<String>>> maps = summaryAllStop(Lists.newArrayList("A1D4", "C2D1", "C1F1", "A2F6").stream().map(DigestUtil::md5Hex).collect(Collectors.toList()));
        maps.forEach(item -> {
            item.keySet().stream().map(item1 ->
                    item.get(item1).stream().map(this::findCode).collect(Collectors.toList())
            ).forEach(System.out::println);
        });
    }


    @Test
    public void flatList() {



      /*  aList.stream().map(item -> bList.stream()
                .map(item1 -> Lists.newArrayList(item, item1)).collect(Collectors.toList()))
                .flatMap(List::stream)
                .forEach(System.out::println);*/

//        all.stream().flatMap(item -> item.stream());


        aList.stream().flatMap(item -> bList.stream()
                .map(item1 -> Lists.newArrayList(item, item1)))
                .flatMap(item2 -> cList.stream().map(item1 -> {
                    ArrayList<String> clone = (ArrayList<String>) item2.clone();
                    clone.add(item1);
                    return clone;
                }))
                .flatMap(item3 -> dList.stream().map(item1 -> {
                    ArrayList<String> clone = (ArrayList<String>) item3.clone();
                    clone.add(item1);
                    return clone;
                }))
                .forEach(System.out::println);


        aList.stream().flatMap(item -> bList.stream()
                .map(item1 -> Lists.newArrayList(item, item1))
                .flatMap(item2 -> cList.stream()
                        .map(item1 -> {
                            ArrayList<String> clone = (ArrayList<String>) item2.clone();
                            clone.add(item1);
                            return clone;
                        }))
                .flatMap(item3 -> dList.stream().map(item1 -> {
                    ArrayList<String> clone = (ArrayList<String>) item3.clone();
                    clone.add(item1);
                    return clone;
                }))
        )
                .forEach(System.out::println);
    }

    /**
     * 根据站点编码生成唯一的站点名称
     */
    @Test
    public void generateStopName() {


        Dict dict = Dict.of("A", 7, "B", 8, "C", 6, "D", 6, "E", 7, "F", 8);

        Map<String, List<String>> asMap = Maps.asMap(Sets.<String>newHashSet("A", "B", "C", "D", "E", "F"), input ->
                IntStream.range(0, dict.getInt(input)).mapToObj(item -> {
                    String stop = input + item;
                    return intersectionList.stream().filter(item2 -> item2.contains(stop)).findFirst().map(item2 -> {
                        String collect = item2.stream().sorted().collect(Collectors.joining());
                        //                    System.out.println("站点<" + collect + ">");
                        //                    System.out.println("#站点编码<"+item1+">交点：" + collect);
                        System.out.println(stop + "=" + DigestUtil.md5Hex(collect));
                        return DigestUtil.md5Hex(collect);
                    }).orElseGet(() -> {
                        //                    System.out.println("#站点<" + item + ">");
                        System.out.println(stop + "=" + DigestUtil.md5Hex(stop));
                        return DigestUtil.md5Hex(stop);
                    });
                }).collect(Collectors.toList())
        );
        asMap.entrySet().stream().forEach(System.out::println);
    }
}
